
// serves for implicitly converted to that type when certain operations cannot be performed 

package scalaSci


class RichDoubleDoubleArray(v: Array[Array[Double]]) {
    private val  value = v    // keeps the  Array[Array[Double]] that this class wraps
    private var  Nrows  = v.length
    private var  Ncols =  v(0).length
    
  

// apply the function f to all the elements of the Matrix and return the results with a new Matrix
 def  map( f: (Double => Double)): Array[Array[Double]] = {
   var mres = new Array[Array[Double]](Nrows, Ncols)
   
    for (r<-0 until Nrows)
      for (c<-0 until Ncols) 
       mres(r)(c) = f(this.v(r)( c) )
   
   mres
 }
 
// adds an Array[Array[Double]] and returns a RichDoubleArray
  def +(that: Double):  Array[Array[Double]]  = {
    var result = new Array[Array[Double]](Nrows, Ncols)
     for (r <-0 until  Nrows)
       for (c<-0 until Ncols)
         result(r)(c) = value(r)(c) + that
 
    result
  }
  
  def -(that: Double):  Array[Array[Double]]  = {
    var result = new Array[Array[Double]](Nrows, Ncols)
     for (r <-0 until  Nrows)
       for (c<-0 until Ncols)
         result(r)(c) = value(r)(c) - that
 
    result
  }
  
  def *(that: Double):  Array[Array[Double]]  = {
    var result = new Array[Array[Double]](Nrows, Ncols)
     for (r <-0 until  Nrows)
       for (c<-0 until Ncols)
         result(r)(c) = value(r)(c)*that
 
    result
  }

  def /(that: Double):  Array[Array[Double]]  = {
    var result = new Array[Array[Double]](Nrows, Ncols)
     for (r <-0 until  Nrows)
       for (c<-0 until Ncols)
         result(r)(c) = value(r)(c) / that
 
    result
  }


  def +(that: Array[Array[Double]]):  Array[Array[Double]]  = {
    var result = new Array[Array[Double]](Nrows, Ncols)
     for (r <-0 until  Nrows)
       for (c<-0 until Ncols)
         result(r)(c) = value(r)(c) + that(r)(c)
 
    result
  }
  
  def -(that: Array[Array[Double]]):  Array[Array[Double]]  = {
    var result = new Array[Array[Double]](Nrows, Ncols)
     for (r <-0 until  Nrows)
       for (c<-0 until Ncols)
         result(r)(c) = value(r)(c) - that(r)(c)
 
    result
  }
  
  
 // Array[Array[Double]] * Array[Array[Double]]
 def * (that: Array[Array[Double]]): Array[Array[Double]] =  {
   var  rN = this.Nrows;   var rM = this.Ncols;
   var  sN = that.length;  var sM = that(0).length

  var  vr =new Array[Array[Double]] (rN, sM)   // for computing the return Matrix

  var   v1Colj = new Array[Double](rM)

   var j=0; var k=0;
   while (j < sM)  {
       k=0
      while  (k < rM) {
        v1Colj(k) =that(k)(j)
        k += 1
      }

      var i=0
      while (i<rN) {
        var   Arowi = this.v(i)
        var   s = 0.0
        k=0
        while (k< rM) {
          s += Arowi(k)*v1Colj(k)
          k += 1
        }
      vr(i)(j) = s;
      i += 1
      }
 j += 1
   }
  return vr
  }

 
// Array[Array[Double]] * Matrix
 def * (that: Matrix): Matrix =  {
   var toMatrix  = new Matrix(this.value)   // convert the 2-D Double Array to Matrix
    
  return toMatrix * that
  }

  
// Array[Array[Double]] * Mat
 def * (that: Mat): Mat =  {
   var toMat  = new Mat(this.value)  // convert the 2-D Double Array to Mat
    
  return toMat * that
  }
  
  
// Array[Array[Double]] * EJMLMat
 def * (that: _root_.scalaSci.EJML.Mat): _root_.scalaSci.EJML.Mat =  {
   var toMat  = new scalaSci.EJML.Mat(this.value)  // convert the 2-D Double Array to Mat
    
  return toMat * that
  }
  
  
   
  def +(that: Matrix): Matrix = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r,c) + value(r)(c)
 
    new Matrix(result, true)
    
  }
  
// subtraction of a Matrix from a RichDoubleArray
  def -(that: Matrix): Matrix = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) =  value(r)(c) - that(r,c) 
 
    new Matrix(result, true)
    
  }

   
  def +(that: Mat): Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r,c) + value(r)(c)
 
    new Mat(result, true)
    
  }
  
// subtraction of a Matrix from a RichDoubleArray
  def -(that: Mat): Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) =  value(r)(c) - that(r,c) 
 
    new Mat(result, true)
    
  }


  
  
  // addition of RichDoubleDoubleArray and an EJML.Mat
 def +( that:  EJML.Mat ): EJML.Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new EJML.Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
         result(r, c) = that(r,c) + value(r)(c)
         c += 1
       }
      r += 1
    }
    result
 }

  // subtraction of an EJML.Mat from a RichDoubleArray
 def -( that:  EJML.Mat ): EJML.Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new EJML.Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
         result(r, c) = -that(r,c) + value(r)(c)
         c += 1
       }
      r += 1
    }
    result
 }


}

